﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Wiyan.Code.PowerMSNRobotLibrary.SDK;
using Wiyan.Code.PowerMSNRobotLibrary.Utility;
using Wiyan.Code.PowerMSNRobotLibrary.Manager;
using XihSolutions.DotMSN.DataTransfer;
using System.IO;

namespace Wiyan.Code.PowerMSNRobotLibrary.Commands
{
    public enum CommandStatus
    {
        Running = 0,
        Stopped = 1,
        Unknown = 2
    }

    public class TextCommandResultBase : ICommandResultBase
    {
        private bool status;
        private string replyMessage;

        public bool Status
        {
            get
            {
                return status;
            }
            set
            {
                status = value;
            }
        }

        public string ReplyMessage
        {
            get
            {
                return replyMessage;
            }
            set
            {
                replyMessage = value;
            }
        }
    }

    public abstract class ExclusiveComanCommandProvider
    {
        protected CommandStatus _status = CommandStatus.Unknown;

        public virtual string EndCommand
        {
            get
            {
                return "-#End";
            }
        }

        public virtual CommandStatus Status
        {
            get
            {
                return _status;
            }
            set
            {
                _status = value;
            }
        }

        public void OnCommandHelp(Object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            foreach (CommandContext subCommand in this.SupportedSubCommands.Values)
            {
                sb.AppendFormat("{0}: {1}\r\n", subCommand.Name, subCommand.Description);
            }

            RobotManager.GetInstance().MessageASyncSender(null, sb.ToString());
        }

        public virtual IDictionary<string, CommandContext> SupportedSubCommands
        {
            get
            {
                Dictionary<string, CommandContext> commands = new Dictionary<string, CommandContext>();

                commands.Add("-#help", new CommandContext("-#help", "list all suppoted commands", new EventHandler(OnCommandHelp)));

                return commands;
            }
        }

        public virtual ErrorCode Start(object parameter)
        {
            //N/A
            Status = CommandStatus.Running;

            return ErrorCode.Success;
        }

        public virtual ErrorCode Close()
        {
            Status = CommandStatus.Stopped;

            //N/A
            return ErrorCode.Success;
        }

        public virtual ErrorCode ProcessSubCommand(string command)
        {
            // Override
            return ErrorCode.Success;
        }
    }

    public class HelpCommandProvider : ICommandProvider
    {
        private static HelpCommandProvider _helpCommandProvider = null;

        public static ICommandProvider GetInstance()
        {
            if (_helpCommandProvider == null)
            {
                _helpCommandProvider = new HelpCommandProvider();
            }

            return _helpCommandProvider;
        }


        public string Name { get { return "help"; } }
        public string Description { get { return "Show help commands"; } }

        private HelpCommandProvider()
        {
        }

        // Session interface
        public bool Initialize(object parameter)
        {
            // N/A

            return true;
        }


        // Command interface
        public ICommandResultBase Run(object[] parameters)
        {
            TextCommandResultBase result = null;

            result = new TextCommandResultBase();

            StringBuilder sbMessage = new StringBuilder();
            sbMessage.AppendLine("Power MSN help system");

            foreach (ICommandProvider commandProvider in RobotManager.GetInstance().SupporttedCommands)
            {
                sbMessage.AppendLine(commandProvider.Name + ":\t" + commandProvider.Description);
            }

            result.Status = true;
            result.ReplyMessage = sbMessage.ToString();

            return result;
        }
    }

    public class GetInformationCommand : ICommandProvider
    {
        private static GetInformationCommand _helpCommandProvider = null;

        public static ICommandProvider GetInstance()
        {
            if (_helpCommandProvider == null)
            {
                _helpCommandProvider = new GetInformationCommand();
            }

            return _helpCommandProvider;
        }

        public string Name { get { return "info"; } }
        public string Description { get { return "Get machine information"; } }

        // Session interface
        public bool Initialize(object parameter)
        {
            // N/A
            return true;
        }

        // Command interface
        public ICommandResultBase Run(object[] parameters)
        {
            TextCommandResultBase result = new TextCommandResultBase();

            string systemInfo = SystemInformation.GetSystemInformation();

            result.Status = true;
            result.ReplyMessage = systemInfo;

            return result;
        }
    }

    public class RAConfigurationCommand : ICommandProvider
    {
        private static RAConfigurationCommand _helpCommandProvider = null;

        public static ICommandProvider GetInstance()
        {
            if (_helpCommandProvider == null)
            {
                _helpCommandProvider = new RAConfigurationCommand();
            }

            return _helpCommandProvider;
        }

        public string Name { get { return "raconfig"; } }
        public string Description { get { return "Get/Set Remote Assistance configuration [enable/disable/query]"; } }

        // Session interface
        public bool Initialize(object parameter)
        {
            // N/A
            return true;
        }

        // Command interface
        public ICommandResultBase Run(object[] parameters)
        {
            TextCommandResultBase result = new TextCommandResultBase();
            string error = string.Empty;
            string running = string.Empty;
            bool callResult;

            if (parameters.Length > 1)
            {
                string setting = parameters[1].ToString();
                switch (setting.ToLower())
                {
                    case "query":
                        running = string.Empty;
                        error = string.Empty;
                        callResult = RAConfigurationHelp.GetConfiguration(ref running, ref error);
                        result.Status = true;
                        result.ReplyMessage = callResult == true ? running : error;
                        break;

                    case "enable":
                        error = string.Empty;
                        callResult = RAConfigurationHelp.SetConfiguration(true, ref error);
                        result.Status = true;
                        result.ReplyMessage = callResult == true ? "Operation success" : error;
                        break;

                    case "disable":
                        error = string.Empty;
                        callResult = RAConfigurationHelp.SetConfiguration(false, ref error);
                        result.Status = true;
                        result.ReplyMessage = callResult == true ? "Operation success" : error;
                        break;

                    default:
                        result.ReplyMessage = "Invalid parameters: For example, rac enable";
                        break;
                }
            }
            else
            {
                // Default as query command
                running = string.Empty;
                error = string.Empty;
                callResult = RAConfigurationHelp.GetConfiguration(ref running, ref error);
                result.Status = true;
                result.ReplyMessage = callResult == true ? running : error;
            }

            result.Status = true;

            return result;
        }
    }

    public class CommandLineCommand : ExclusiveComanCommandProvider, ICommandProvider
    {
        private static CommandLineCommand _helpCommandProvider = null;

        private CommandLineCommand()
        {
        }

        public static ICommandProvider GetInstance()
        {
            if (_helpCommandProvider == null)
            {
                _helpCommandProvider = new CommandLineCommand();
            }

            return _helpCommandProvider;
        }

        public string Name { get { return "cmd"; } }
        public string Description { get { return "Open a command prompt session to run command at the remote machine"; } }

        // Session interface
        public bool Initialize(object parameter)
        {
            // N/A
            return true;
        }

        // Command interface
        public ICommandResultBase Run(object[] parameters)
        {
            throw new Exception("Should not hit here");
        }

        override public ErrorCode Start(object parameter)
        {
            base.Start(parameter);

            ErrorCode errorCode = CommandLineHelper.GetInstance().StartWorker(parameter);

            return errorCode;
        }

        override public ErrorCode Close()
        {
            base.Close();

            ErrorCode errorCode = CommandLineHelper.GetInstance().CloseWorker(null);

            return errorCode;
        }

        override public ErrorCode ProcessSubCommand(string command)
        {
            string output = string.Empty;
            ErrorCode errorCode = CommandLineHelper.GetInstance().RunCommand(command, ref output);

            return errorCode;
        }
    }

    public class RACommand : ExclusiveComanCommandProvider, ICommandProvider
    {
        private VistaRemoteAssistanceHelper _raHelper = null;
        private static ICommandProvider _helpCommandProvider = null;

        public void OnCommandStop(Object sender, EventArgs e)
        {
            if (_raHelper != null)
            {
                _raHelper.StopRASession();
            }
        }

        public void OnCommandKill(Object sender, EventArgs e)
        {
            if (_raHelper != null)
            {
                _raHelper.KillByForce();
            }
        }

        public void OnCommandAllow(Object sender, EventArgs e)
        {
            if (_raHelper != null)
            {
                _raHelper.Allow();
            }
        }

        public void OnCommandControl(Object sender, EventArgs e)
        {
            if (_raHelper != null)
            {
                _raHelper.Allow();
            }
        }

        override public IDictionary<string, CommandContext> SupportedSubCommands
        {
            get
            {
                Dictionary<string, CommandContext> raSupportedCommands = new Dictionary<string,CommandContext>();

                foreach (KeyValuePair<string, CommandContext> kvp in base.SupportedSubCommands)
                {
                    raSupportedCommands.Add(kvp.Key, kvp.Value);
                }

                raSupportedCommands.Add("stop", new CommandContext("stop", "stop ra session", OnCommandStop));
                raSupportedCommands.Add("kill", new CommandContext("kill", "kill msra process by force", OnCommandKill));
                raSupportedCommands.Add("control", new CommandContext("control", "allow share the control to me", OnCommandControl));
                raSupportedCommands.Add("allow", new CommandContext("allow", "allow share the control to me", OnCommandAllow));

                return raSupportedCommands;
            }
        }

        private RACommand()
        {
        }

        public static ICommandProvider GetInstance()
        {
            if (_helpCommandProvider == null)
            {
                _helpCommandProvider = new RACommand();
            }

            return _helpCommandProvider;
        }

        public string Name { get { return "ra"; } }
        public string Description { get { return "Windows Remote Assistance session auto self center"; } }

        // Session interface
        public bool Initialize(object parameter)
        {
            // N/A
            return true;
        }

        // Command interface
        public ICommandResultBase Run(object[] parameters)
        {
            throw new Exception("Should not hit here");
        }

        override public ErrorCode Start(object parameter)
        {
            base.Start(parameter);
            string path = string.Empty;

            _raHelper = new VistaRemoteAssistanceHelper(RobotManager.GetInstance().MessageASyncSender);
            ErrorCode error = _raHelper.GenerateRATicket("User@123", ref path);
            RobotManager manager = RobotManager.GetInstance();
            if (error == ErrorCode.Success)
            {
                if (manager.MessageASyncSender != null)
                {
                    manager.MessageASyncSender.Invoke(null,
                        string.Format("Remote Assistance session is ready, ticket file is generated in {0}, please accept this file to establish the session.", path));
                }

                // Transfer file to remote machine
                MSNSLPHandler msnslpHandler = manager.Messenger.GetMSNSLPHandler(RobotManager.GetInstance().CurrentContact.Mail);
                FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                P2PTransferSession session = msnslpHandler.SendInvitation(manager.Messenger.Owner.Mail, RobotManager.GetInstance().CurrentContact.Mail, Path.GetFileName(path), fileStream);
            }

            return error;
        }

        override public ErrorCode Close()
        {
            base.Close();

            if (_raHelper != null)
            {
                _raHelper.StopRASession();
                _raHelper.Dispose();
                _raHelper = null;
            }

            return ErrorCode.Success;
        }

        override public ErrorCode ProcessSubCommand(string command)
        {
            string output = string.Empty;
            ErrorCode error = ErrorCode.Success;

            if(this.SupportedSubCommands.ContainsKey(command))
            {
                if (this.SupportedSubCommands[command].OnCommand != null)
                    this.SupportedSubCommands[command].OnCommand.Invoke(null, null);
            }

            return error;
        }
    }
}
